package com.joker.airoleplayplatformback.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.joker.airoleplayplatformback.service.VoiceChatService;
import com.joker.airoleplayplatformback.utils.WebSocketConnectionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.util.Map;

/**
 * 语音聊天WebSocket处理器
 */
@Slf4j
@Component
public class VoiceChatWebSocketHandler extends AbstractWebSocketHandler {

    @Autowired
    @Lazy
    private VoiceChatService voiceChatService;

    @Autowired
    private WebSocketConnectionManager connectionManager;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String sessionId = session.getId();

        // 注册会话到连接管理器
        connectionManager.registerSession(sessionId, session);

        // 注册自己到语音聊天服务
        voiceChatService.registerHandler(sessionId, this);

        log.info("WebSocket连接建立: {}", sessionId);

        // 发送连接成功消息
        connectionManager.sendConnectionMessage(sessionId);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String sessionId = session.getId();
        String payload = message.getPayload();
        log.info("收到文本消息，会话: {}, 内容: {}", sessionId, payload);

        try {
            Map<String, Object> messageData = objectMapper.readValue(payload, Map.class);
            String type = (String) messageData.get("type");

            switch (type) {
                case "init":
                    handleInitMessage(session, messageData);
                    break;
                case "voice_start":
                    handleVoiceStart(session, messageData);
                    break;
                case "voice_end":
                    handleVoiceEnd(session, messageData);
                    break;
                case "voice_message":
                    handleVoiceMessage(session, messageData);
                    break;
                case "stop_audio":
                    handleStopAudio(session, messageData);
                    break;
                case "heartbeat":
                    handleHeartbeat(session, messageData);
                    break;
                default:
                    log.warn("未知消息类型: {}", type);
            }
        } catch (Exception e) {
            log.error("处理文本消息失败", e);
            connectionManager.sendErrorMessage(sessionId, "消息处理失败: " + e.getMessage());
        }
    }

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
        String sessionId = session.getId();
        byte[] audioData = message.getPayload().array();
        log.info("收到音频数据，会话: {}, 数据大小: {} bytes", sessionId, audioData.length);

        try {
            // 处理音频数据流
            voiceChatService.processAudioStream(sessionId, audioData, this);
        } catch (Exception e) {
            log.error("处理音频数据失败", e);
            connectionManager.sendErrorMessage(sessionId, "音频处理失败: " + e.getMessage());
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        String sessionId = session.getId();
        log.error("WebSocket传输错误，会话: {}", sessionId, exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        String sessionId = session.getId();

        // 从连接管理器中注销会话
        connectionManager.unregisterSession(sessionId);

        // 从语音聊天服务中注销
        voiceChatService.unregisterHandler(sessionId);

        log.info("WebSocket连接关闭: {}, 状态: {}", sessionId, closeStatus);
    }

    /**
     * 处理初始化消息
     */
    private void handleInitMessage(WebSocketSession session, Map<String, Object> messageData) {
        String sessionId = session.getId();
        Long userId = Long.parseLong(messageData.get("userId").toString());
        String agentId = (String) messageData.get("agentId");
        String chatSessionId = (String) messageData.get("chatSessionId");

        // 设置会话用户信息
        connectionManager.setSessionUser(sessionId, userId);

        // 初始化聊天会话
        voiceChatService.initChatSession(sessionId, userId, agentId, chatSessionId);

        connectionManager.sendInitSuccessMessage(sessionId);
    }

    /**
     * 处理语音开始消息
     */
    private void handleVoiceStart(WebSocketSession session, Map<String, Object> messageData) {
        String sessionId = session.getId();
        log.info("开始录音，会话: {}", sessionId);

        connectionManager.sendVoiceRecordingStartMessage(sessionId);
    }

    /**
     * 处理语音结束消息
     */
    private void handleVoiceEnd(WebSocketSession session, Map<String, Object> messageData) {
        String sessionId = session.getId();
        log.info("结束录音，会话: {}", sessionId);

        // 通知语音服务处理完整的音频
        voiceChatService.finishAudioRecording(sessionId);

        connectionManager.sendVoiceProcessingMessage(sessionId);
    }

    /**
     * 处理语音消息（包含音频数据）
     */
    private void handleVoiceMessage(WebSocketSession session, Map<String, Object> messageData) {
        String sessionId = session.getId();
        log.info("收到语音消息，会话: {}", sessionId);

        try {
            // 获取音频数据
            Object audioDataObj = messageData.get("audioData");
            if (audioDataObj == null) {
                log.warn("语音消息中没有音频数据");
                return;
            }

            byte[] audioData;
            if (audioDataObj instanceof String) {
                // Base64编码的音频数据
                audioData = java.util.Base64.getDecoder().decode((String) audioDataObj);
            } else if (audioDataObj instanceof byte[]) {
                audioData = (byte[]) audioDataObj;
            } else {
                log.warn("不支持的音频数据格式: {}", audioDataObj.getClass());
                return;
            }

            // 保存音频文件到临时目录
            String audioFileName = "voice_msg_" + System.currentTimeMillis() + ".mp3";
            String tempFilePath = System.getProperty("java.io.tmpdir") + java.io.File.separator + audioFileName;

            try (java.io.FileOutputStream fos = new java.io.FileOutputStream(tempFilePath)) {
                fos.write(audioData);
                log.info("语音消息保存到临时文件: {}, 大小: {} bytes", tempFilePath, audioData.length);

                // 通知语音服务处理音频文件
                voiceChatService.processVoiceFile(sessionId, tempFilePath);

                // 发送处理中消息
                connectionManager.sendVoiceProcessingMessage(sessionId);

            } catch (java.io.IOException e) {
                log.error("保存语音消息文件失败", e);
                connectionManager.sendErrorMessage(sessionId, "保存语音文件失败");
            }

        } catch (Exception e) {
            log.error("处理语音消息失败", e);
            connectionManager.sendErrorMessage(sessionId, "处理语音消息失败: " + e.getMessage());
        }
    }

    /**
     * 处理停止音频播放消息
     */
    private void handleStopAudio(WebSocketSession session, Map<String, Object> messageData) {
        String sessionId = session.getId();
        log.info("停止音频播放，会话: {}", sessionId);

        connectionManager.sendAudioStoppedMessage(sessionId);
    }

    /**
     * 处理心跳消息
     */
    private void handleHeartbeat(WebSocketSession session, Map<String, Object> messageData) {
        String sessionId = session.getId();

        // 更新心跳时间
        connectionManager.updateHeartbeat(sessionId);

        // 回复心跳响应
        connectionManager.sendHeartbeatResponse(sessionId);

        log.debug("收到心跳: {}", sessionId);
    }

    /**
     * 获取所有会话（供心跳检测使用）
     */
    public Map<String, WebSocketSession> getSessions() {
        return connectionManager.getAllSessions();
    }

    /**
     * 获取心跳时间映射（供心跳检测使用）
     */
    public Map<String, Long> getSessionHeartbeatMap() {
        return connectionManager.getHeartbeatMap();
    }
}
